package ru.teleology.cubefs.tests;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import org.junit.Test;

import ru.teleology.cubefs.api.models.TreeMap;
import ru.teleology.cubefs.api.models.TreeMapIterator;
import ru.teleology.cubefs.api.models.Map.Pair;
import ru.teleology.cubefs.api.reflection.list.StaticListOfTyped;
import ru.teleology.cubefs.api.reflection.number.Number;

public class KVMapTest extends ContainerTestBase {

	private static final int SIZE = 1000 - 1;
	
	private long[][] pairs = new long[SIZE][2];
	private List<long[]> pairs_sorted = new ArrayList<long[]>();
	
	Comparator<long[]> pair_comparator = new Comparator<long[]>(){
		public int compare(long[] o1, long[] o2) {
			long result = o1[0] - o2[0];
			return result < 0 ? -1 : result > 0 ? 1 : 0;
		}
	};
	
	public KVMapTest() {
		Random RND = new Random(0);
		
		for (int c = 0; c < pairs.length; c++) {
			long key 	= (RND.nextLong() & 0x7fffffffffffffffl);
			long value 	= (RND.nextLong() & 0x7fffffffffffffffl);
			
			pairs[c][0] 		= key;
			pairs[c][1] 		= value;
		}
	}
	
	@Test
	public void test() {
		setChildrenPerNode(5);
		
		final TreeMap map 	= (TreeMap) container.CreateCollection(2, 1);
		
		map.SetMaxChildrenPerNode(getChildrenPerNode());
		
		final TreeMap.Pair pair 	=  map.CreatePairHolder();
		final StaticListOfTyped keys 		= (StaticListOfTyped) pair.key();
		final Number key 		= (Number) keys.get(0);
		final Number value 		= (Number) pair.value();
		
		run(new Ops("KVMap_createRemove") {{
			for (int c = 0; c < SIZE; c++) {
				final int cc = c;
				System.err.println(cc+" "+Runtime.getRuntime().freeMemory()/1024/1024);
				run(new Op(cc+".CreateOp"){{
					key.SetValue(pairs[cc][0]);
					value.SetValue(pairs[cc][1]);
					map.Put(pair);
					
					assertEquals(cc + 1, map.GetSize());
					assertEquals(false, container.Check());
					
					pairs_sorted.add(pairs[cc]);
					sort(pairs_sorted);
					
					checkIterator(map, pair, pairs_sorted);
				}});
			}
			
			for (int c = 0; c < SIZE; c++) {
				final int cc = c;
				run(new Op(cc+".QueryOp"){{
					key.SetValue(pairs[cc][0]);
					map.Get(pair);
					
					assertEquals(pairs[cc][1], value.GetBigIntValue());
				}});
			}
			
			for (int c = 0; c < SIZE; c++) {
				final int cc = c;
				run(new Op(cc+".RemoveOp"){{
					key.SetValue(pairs[cc][0]);
					map.Remove(pair);

					long size = SIZE - cc - 1;
					assertEquals(size, map.GetSize());
					assertEquals(false, container.Check());

					pairs_sorted.remove(pairs[cc]);

					checkIterator(map, pair, pairs_sorted);
				}});
			}

			assertEquals(0, container.GetManager().GetPageCount());
			assertEquals(false, container.Check());

//			System.gc();
//			System.gc();
		}});
		
//		System.gc();
//		System.gc();
		System.err.println("--------------------------------");
		System.err.println(Runtime.getRuntime().freeMemory()/1024/1024);
	}
	
	private void sort(List<long[]> list) {
		Collections.sort(list, pair_comparator);
	}
	
	private void checkIterator(TreeMap map, Pair pair, List<long[]> pairs) {
		TreeMapIterator iter = (TreeMapIterator) map.CreateIterator();
		final StaticListOfTyped keys 	= (StaticListOfTyped) pair.key();
		final Number key 				= (Number) keys.get(0);
		final Number value 				= (Number) pair.value();
		
		int idx = 0;
		while (!iter.IsEof()) {
			iter.GetValue(pair);
			
			assertEquals(pairs.get(idx)[0], key.GetBigIntValue());
			assertEquals(pairs.get(idx)[1], value.GetBigIntValue());
			
			iter.Next();
			idx++;
		}
		
		assertEquals(pairs.size(), idx);
	}
	
}
